﻿using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
using System.IO;
#endif

namespace Core.Runtime
{
    public abstract class ScriptableSingleton<T> : ScriptableObject where T : ScriptableObject
    {
        private static T s_Instance;

        protected abstract string AssetPath { get; }
        protected abstract string ResourcePath { get; }

        public static T Instance
        {
            get
            {
                if (s_Instance == null)
                {
                    LoadOrCreate();
                }

                return s_Instance;
            }
        }

        private static void LoadOrCreate()
        {
#if UNITY_EDITOR
            LoadOrCreateInEditor();
#else
            LoadFromResources();
#endif
        }

#if UNITY_EDITOR
        private static void LoadOrCreateInEditor()
        {
            string[] guids = UnityEditor.AssetDatabase.FindAssets($"t:{typeof(T).Name}");
            if (guids.Length == 0)
            {
                CreateNewAsset();
            }
            else
            {
                LoadExistingAsset(guids);
            }
        }

        private static void CreateNewAsset()
        {
            s_Instance = CreateInstance<T>();
            var path = (s_Instance as ScriptableSingleton<T>)?.AssetPath;
            EnsureDirectoryExists(path);
            UnityEditor.AssetDatabase.CreateAsset(s_Instance, path);
            UnityEditor.AssetDatabase.SaveAssets();
            Debug.Log($"Created {typeof(T).Name} at {path}");
        }

        private static void LoadExistingAsset(string[] guids)
        {
            if (guids.Length > 1)
            {
                Debug.LogWarning($"Multiple {typeof(T).Name} assets found!");
                foreach (var guid in guids)
                {
                    Debug.LogWarning(UnityEditor.AssetDatabase.GUIDToAssetPath(guid));
                }
            }

            var path = UnityEditor.AssetDatabase.GUIDToAssetPath(guids[0]);
            s_Instance = UnityEditor.AssetDatabase.LoadAssetAtPath<T>(path);
        }

        private static void EnsureDirectoryExists(string path)
        {
            string directory = Path.GetDirectoryName(path);
            if (!Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory);
                UnityEditor.AssetDatabase.Refresh();
            }
        }
#endif

        private static void LoadFromResources()
        {
            s_Instance = Resources.Load<T>((s_Instance as ScriptableSingleton<T>)?.ResourcePath);
            if (s_Instance == null)
            {
                Debug.LogError($"Failed to load {typeof(T).Name} from resources!");
            }
        }
    }
}